package locations.dao.implement;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;

import locations.dao.GenericDAO;

public class GenericDAOHibernateJPA<T> implements GenericDAO<T> {

  protected Class<T> type;
  protected EntityManager entityManager;
  protected EntityTransaction transaction;
  protected CriteriaBuilder criteriaBuilder;

  public GenericDAOHibernateJPA() {
    super();
    this.entityManager = Persistence.createEntityManagerFactory("locations").createEntityManager();
    this.transaction = entityManager.getTransaction();
    this.criteriaBuilder = entityManager.getCriteriaBuilder();
  }

  public GenericDAOHibernateJPA(Class<T> type) {
    this();
    this.type = type;
  }

  public T save(T o) {
    this.getTransaction().begin();
    T entity = this.getEntityManager().merge(o);
    this.getTransaction().commit();
    return entity;
  }

  public T delete(long id) {
    this.getTransaction().begin();
    T entity = this.getEntityManager().find(this.getType(), id);
    this.getEntityManager().remove(entity);
    this.getEntityManager().close();
    this.getTransaction().commit();
    return entity;
  }

  public List<T> retrieveAll() {
    this.getTransaction().begin();
    CriteriaQuery q = criteriaBuilder.createQuery();
    Root<T> c = q.from(type);
    q.select(c);
    TypedQuery<T> query = this.getEntityManager().createQuery(q);
    List<T> list = query.getResultList();
    this.getTransaction().commit();
    return list;
  }

  public T retrieveById(long id) {
    this.getTransaction().begin();
    T entity = this.getEntityManager().find(this.getType(), id);
    this.getTransaction().commit();
    return entity;
  }

  public Class<T> getType() {
    return type;
  }

  public void setType(Class<T> type) {
    this.type = type;
  }

  public EntityManager getEntityManager() {
    return entityManager;
  }

  public void setEntityManager(EntityManager entityManager) {
    this.entityManager = entityManager;
  }

  public EntityTransaction getTransaction() {
    return transaction;
  }

  public void setTransaction(EntityTransaction transaction) {
    this.transaction = transaction;
  }

  public CriteriaBuilder getCriteriaBuilder() {
    return criteriaBuilder;
  }

  public void setCriteriaBuilder(CriteriaBuilder criteriaBuilder) {
    this.criteriaBuilder = criteriaBuilder;
  }
}
